package com.js.service.bot.basics;

import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.js.common.constant.BotConst;
import com.js.common.constant.Const;
import com.js.common.core.BotWebSocketClient;
import com.js.common.exception.AjaxException;
import com.js.domian.entity.bot.WebsocketEntity;
import com.js.domian.vo.bot.WebsocketVo;
import com.js.mapper.bot.WebsocketMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Slf4j
@Service
@RequiredArgsConstructor
public class WebsocketService {

    private final WebsocketMapper websocketMapper;
    private final ResponseService responseService;

    public List<WebsocketEntity> getWebsocketList(WebsocketVo vo){
        PageHelper.startPage(vo);
        List<WebsocketEntity> list = websocketMapper.getWebsocketList(vo);
        for (WebsocketEntity entity : list) {
            boolean isOpen = BotConst.webSocketClientMap.get(entity.getQq()).isOpen();
            if(isOpen){
                entity.setConnectStatus(Const.BASE_YES_NO.YES.getValue());
            }else {
                entity.setConnectStatus(Const.BASE_YES_NO.NO.getValue());
            }
        }
        return list;
    }

    public WebsocketEntity getWebsocketByUrl(String url){
        return websocketMapper.getWebsocketByUrl(url);
    }

    public List<WebsocketEntity> getAllWebsocketList(){
        return websocketMapper.getWebsocketList(new WebsocketVo());
    }

    @Transactional(rollbackFor = Exception.class)
    public void addWebsocket(WebsocketEntity entity) throws ExecutionException, InterruptedException {
        if(entity.getId() == null){
            websocketMapper.addWebsocket(entity);
        }else{
            websocketMapper.updateWebsocket(entity);
        }
        CompletableFuture<Boolean> future = generateWebSocketClient(entity);
        if(!future.get()){
            throw new AjaxException("保存成功但启动失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteWebsocket(Integer id){
        WebsocketEntity entity = websocketMapper.getWebsocket(id);
        BotConst.webSocketClientMap.get(entity.getQq()).close();
        BotConst.webSocketClientMap.remove(entity.getQq());
        websocketMapper.deleteWebsocket(id);
        responseService.deleteResponseByWebsocketId(id);
    }

    public void connect(WebsocketEntity entity){
        if(Const.BASE_YES_NO.YES.getValue().equals(entity.getConnectStatus())){
            websocketStart(entity.getQq(), entity.getUrl());
        }else if(BotConst.webSocketClientMap.get(entity.getQq()).isOpen()){
            BotConst.webSocketClientMap.get(entity.getQq()).close();
        }
    }

    @Async("wsExecutor")
    public CompletableFuture<Boolean> generateWebSocketClient(WebsocketEntity entity){
        boolean success = true;
        try {
            Map<String, String> httpHeaders = new HashMap<>();
            if(StrUtil.isNotEmpty(entity.getToken())){
                httpHeaders.put("Authorization", "Bearer " + entity.getToken());
            }
            WebSocketClient webSocketClient = new BotWebSocketClient(new URI(entity.getUrl()), httpHeaders);
            /**webSocketClient.connect();
             Timer t = new Timer();
             t.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
            //                    System.out.println("进入定时器");
            if(webSocketClient.isClosed()){
            //                        log.error("断线重连");
            webSocketClient.reconnect();
            }
            }
            },1000,5000);*/
            BotConst.webSocketClientMap.put(entity.getQq(), webSocketClient);
            if(Const.BASE_YES_NO.YES.getValue().equals(entity.getAutoStart())){
                websocketStart(entity.getQq(), entity.getUrl());
            }
        } catch (URISyntaxException e) {
            log.error("===================>启动失败", e);
            success = false;
        }
        return CompletableFuture.completedFuture(success);
    }

    public void websocketStart(Long qq, String url){
        WebSocketClient client = BotConst.webSocketClientMap.get(qq);
        if (!client.isOpen()) {
            if (client.getReadyState().equals(ReadyState.NOT_YET_CONNECTED)) {
                try {
                    client.connect();
                } catch (IllegalStateException e) {
                }
            } else if (client.getReadyState().equals(ReadyState.CLOSING) || client.getReadyState().equals(ReadyState.CLOSED)) {
                client.reconnect();
            }
        }
    }
}
